package com.koron.css2.contractmanage.impl;

import com.koron.css2.AccessoryInterface;
import com.koron.css2.ApplicationConfig;
import com.koron.css2.common.bean.FileProBean;
import com.koron.css2.common.bean.MultipartContentBean;
import com.koron.css2.common.utils.HttpUtils;
import com.koron.css2.contractmanage.Enum.ContractStatusEnum;
import com.koron.css2.contractmanage.Enum.ContractTypeEnum;
import com.koron.css2.contractmanage.bean.ContractManageBean;
import com.koron.css2.contractmanage.exception.ContractException;
import com.koron.css2.contractmanage.mapper.ContractManageMapper;
import com.koron.css2.contractmanage.util.FileUploadVerify;
import com.koron.css2.serviceManage.bean.RequestBean;
import com.koron.css2.serviceManage.bean.UserInfoBean;
import com.koron.css2.serviceManage.utils.JsonUtils;
import com.koron.util.Constant;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.koron.ebs.mybatis.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.web.multipart.MultipartFile;
import org.swan.bean.MessageBean;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 合同附件上传
 */
public class ContractAccessoryUpload implements AccessoryInterface {

    private static Logger log = LoggerFactory.getLogger(ContractAccessoryUpload.class);

    /**
     * 文件服务器地址
     */
    private static final String ACCESSORY_UPLOAD_URL = ApplicationConfig.getAccessoryUploadUrl();

    /**
     * 文件服务器认证参数
     */
    private static Map<String, String> accessoryMap = new HashMap<>(2);

    /**
     * 签约进行中、已上传合同附件、签约完成状态才能上传附件
     */
    private static final String ALLOW_UPLOAD_FILE_CONTRACT_STATUS =  ContractStatusEnum.CONTRACT_STATUS_1.getContractStatus() + ","
            + ContractStatusEnum.CONTRACT_STATUS_2.getContractStatus() + ","
            + ContractStatusEnum.CONTRACT_STATUS_7.getContractStatus();

    /**
     * 初始化文件服务器认证参数
     */
    static {
        accessoryMap.put("appid", ApplicationConfig.getAccessoryAppId());
        accessoryMap.put("secret", ApplicationConfig.getAccessorySecret());
    }


    /**
     * 合同文件附件上传
     *
     * @param factory
     * @param userInfo
     * @param req
     * @param files
     * @return
     */
    @Override
    public MessageBean<?> upload(SessionFactory factory, UserInfoBean userInfo, RequestBean req, List<MultipartFile> files) {
        try {
            //校验文件附件数量
            checkFileNumber(files);
            //校验合同字段
            ContractManageBean bean = JsonUtils.objectToPojo(req.getData(), ContractManageBean.class);
            checkContractManageBean(bean.getId(), bean.getProjectId(), bean.getContractNo(), bean.getContractType(), userInfo);

            //取出文件附件
            MultipartFile file = files.get(0);
            //校验文件附件类型、名称、大小
            FileUploadVerify.uploadVerify(file);
            //获取认证服务器的token
            String fToken = getFToken();
            //上传合同文件到文件服务器,并获取上传文件的相对路径
            String path = uploadContractFile(fToken, file);
            //组装合同文件附件下载地址
            String contractFileAddr = ACCESSORY_UPLOAD_URL + Constant.FILE_DOWNLOAD + path;
            // 文件名称
            String contractFileName = file.getOriginalFilename();

            ContractManageMapper mapper = factory.getMapper(ContractManageMapper.class);

            // 获取合同信息
            ContractManageBean contractManageBean = getContractManageBean(bean, mapper);
            // 更新合同信息
            int updateContract = updateContract(contractManageBean, userInfo, mapper, path, contractFileName);

            if (updateContract < 1) {
                throw new ContractException("更新合同附件信息失败！");
            }

            HashMap<String, Object> filePathMap = new HashMap<>(3);
            filePathMap.put("contractFileAddr", path);
            filePathMap.put("contractFileDownUrl", contractFileAddr);
            filePathMap.put("contractFileName", contractFileName);
            MessageBean<Map> messageBean = MessageBean.create(Constant.MESSAGE_INT_SUCCESS, "上传合同附件成功", Map.class);
            messageBean.setData(filePathMap);
            return messageBean;
        } catch (Exception e) {
            log.error("合同附件上传失败：" + e.getMessage(), e);
            return MessageBean.create(Constant.MESSAGE_INT_FAIL, "合同附件上传失败：" + e.getMessage(), null);
        }
    }

    /**
     * 封装请求参数，上传合同文件附件到文件服务器
     *
     * @return
     */
    public String uploadContractFile(String fToken, MultipartFile file) throws IOException {
        FileProBean filePro = new FileProBean();
        Map<String, String> data = new HashMap<>(1);
        List<MultipartContentBean> multipartContents = new ArrayList<>();
        MultipartContentBean multipartContent = new MultipartContentBean();
        multipartContent.setBytes(file.getBytes());
        multipartContent.setContentType(file.getContentType());
        multipartContent.setFileName(FilenameUtils.getName(file.getOriginalFilename()));
        multipartContents.add(multipartContent);
        data.put("ftoken", fToken);
        filePro.setData(data);
        filePro.setMultipart(multipartContents);
        String result = HttpUtils.upload(ACCESSORY_UPLOAD_URL + Constant.FILE_UPLOAD, filePro);
        MessageBean<?> message = JsonUtils.jsonToPojo(result, MessageBean.class);
        if (message.getCode() != Constant.MESSAGE_INT_SUCCESS) {
            throw new ContractException("文件服务器上传合同附件失败：" + message.getDescription());
        }
        Map<String, String> map = JsonUtils.objectToPojo(message.getData(), Map.class);
        String path = map.get("path");
        if (StringUtils.isBlank(path)) {
            throw new ContractException("获取合同附件相对路径为空：" + message.getDescription());
        }
        return path;
    }


    /**
     * 认证文件服务器，并获取token
     *
     * @return
     */
    public String getFToken() {
        String result = HttpUtils.sendPostJson(ACCESSORY_UPLOAD_URL + Constant.FILE_AUTHORIZE, JsonUtils.objectToJson(accessoryMap));
        MessageBean<?> message = JsonUtils.jsonToPojo(result, MessageBean.class);
        if (message.getCode() != Constant.MESSAGE_INT_SUCCESS) {
            throw new ContractException("认证文件服务器失败,获取fToken失败：" + message.getDescription());
        }
        Map<String, String> resultMap = JsonUtils.objectToPojo(message.getData(), Map.class);
        return resultMap.get("ftoken");
    }

    /**
     * 判断传入的文件数量是否正确
     *
     * @param files
     */
    public void checkFileNumber(List<MultipartFile> files) {
        if (files == null || files.isEmpty()) {
            throw new ContractException("上传的合同附件不能为空！");
        }
        if (files.size() > 1) {
            throw new ContractException("只能上传一个合同附件！");
        }
        if (files.get(0) == null) {
            throw new ContractException("上传的合同附件不能为空！");
        }
    }

    /**
     *
     * @param bean
     * @param mapper
     * @return
     */
    private ContractManageBean getContractManageBean(ContractManageBean bean, ContractManageMapper mapper) {
        String projectId = bean.getProjectId();
        String contractNo = bean.getContractNo();
        ContractManageBean contractManageBean = mapper.getContractDetail(projectId, contractNo);
        if (contractManageBean == null || StringUtils.isBlank(contractManageBean.getContractNo())) {
            throw new ContractException("根据合同编号" + bean.getContractNo() + "找不到合同！");
        }

        String contractStatus = contractManageBean.getContractStatus();
        if (!ALLOW_UPLOAD_FILE_CONTRACT_STATUS.contains(contractStatus)) {
            //签约进行中、已上传合同附件、签约完成状态才能上传附件
            throw new ContractException("只有签约进行中、已上传合同附件、签约完成状态的合同才能上传附件！");
        }
        return contractManageBean;
    }

    /**
     * 更新合同表签约成功状态
     *
     * @param bean
     * @param userInfo
     * @param mapper
     * @return
     */
    private int updateContract(ContractManageBean bean, UserInfoBean userInfo, ContractManageMapper mapper, String path, String contractFileName) {
        ContractManageBean updateContractBean = new ContractManageBean();
        updateContractBean.setProjectId(bean.getProjectId());
        updateContractBean.setContractNo(bean.getContractNo());

        updateContractBean.setContractFileAddr(path);
        updateContractBean.setContractFileName(contractFileName);
        updateContractBean.setUpdateInfo(userInfo);
        return mapper.updateContract(updateContractBean);
    }

    @Override
    public HttpEntity<?> down(SessionFactory factory, UserInfoBean userInfo, RequestBean req) {
        return null;
    }

    /**
     * 校验合同字段
     *
     * @param projectId
     * @param contractType
     * @return
     */
    private void checkContractManageBean(String id, String projectId, String contractNo, String contractType, UserInfoBean userInfo) {
        if (userInfo == null) {
            throw new ContractException("用户信息不能为空！");
        }
//        if (StringUtils.isBlank(id)) {
//            throw new ContractException("合同ID不能为空，必须生成合同后才能上传附件！");
//        }
        if (StringUtils.isBlank(projectId)) {
            throw new ContractException("参数中的报装单ID不能为空！");
        }
        if (StringUtils.isBlank(contractNo)) {
            throw new ContractException("参数中的合同编码不能为空！");
        }
        if (StringUtils.isBlank(contractType)) {
            throw new ContractException("参数中的合同类型不能为空！");
        }
        if (ContractTypeEnum.CONTRACT_TYPE_2.getContractType().equals(contractType)) {
            throw new ContractException("电子合同不能自行上传附件！");
        }
    }
}

